#include "device.h"
#include "component.h"

#define GSENSOR_LOG(format, ...)    OSAL_LOG(C_BLUE format C_NONE, ##__VA_ARGS__)
#define __GSENSOR_LOG(format, ...)  __OSAL_LOG(C_BLUE format C_NONE, ##__VA_ARGS__)


/* Virtual hardware interface */
#define IIC_VHW_GSENSOR         vIIC_0
#define IRQ_VHW_GSENSOR         vPIN_I0

/* I2C Device Address 7 bit format */
#define IIC_ADDR_GSENSOR               0X1E

/* Device Identification (Who am I) */
#define LIS2DS12_ID                    0x43U

#define LIS2DS12_SENSORHUB1_REG        0x06U
#define LIS2DS12_SENSORHUB2_REG        0x07U
#define LIS2DS12_SENSORHUB3_REG        0x08U
#define LIS2DS12_SENSORHUB4_REG        0x09U
#define LIS2DS12_SENSORHUB5_REG        0x0AU
#define LIS2DS12_SENSORHUB6_REG        0x0BU
#define LIS2DS12_MODULE_8BIT           0x0CU
#define LIS2DS12_WHO_AM_I              0x0FU
#define LIS2DS12_CTRL1                 0x20U
#define LIS2DS12_CTRL2                 0x21U
#define LIS2DS12_CTRL3                 0x22U
#define LIS2DS12_CTRL4                 0x23U
#define LIS2DS12_CTRL5                 0x24U
#define LIS2DS12_FIFO_CTRL             0x25U
#define LIS2DS12_OUT_T                 0x26U
#define LIS2DS12_STATUS                0x27U
#define LIS2DS12_OUT_X_L               0x28U
#define LIS2DS12_OUT_X_H               0x29U
#define LIS2DS12_OUT_Y_L               0x2AU
#define LIS2DS12_OUT_Y_H               0x2BU
#define LIS2DS12_OUT_Z_L               0x2CU
#define LIS2DS12_OUT_Z_H               0x2DU
#define LIS2DS12_FIFO_THS              0x2EU
#define LIS2DS12_FIFO_SRC              0x2FU
#define LIS2DS12_FIFO_SAMPLES          0x30U
#define LIS2DS12_TAP_6D_THS            0x31U
#define LIS2DS12_INT_DUR               0x32U
#define LIS2DS12_WAKE_UP_THS           0x33U
#define LIS2DS12_WAKE_UP_DUR           0x34U
#define LIS2DS12_FREE_FALL             0x35U
#define LIS2DS12_STATUS_DUP            0x36U
#define LIS2DS12_WAKE_UP_SRC           0x37U
#define LIS2DS12_TAP_SRC               0x38U
#define LIS2DS12_6D_SRC                0x39U
#define LIS2DS12_STEP_COUNTER_MINTHS   0x3AU
#define LIS2DS12_STEP_COUNTER_L        0x3BU
#define LIS2DS12_STEP_COUNTER_H        0x3CU
#define LIS2DS12_FUNC_CK_GATE          0x3DU
#define LIS2DS12_FUNC_SRC              0x3EU
#define LIS2DS12_FUNC_CTRL             0x3FU

/*******************************************************************************
* Register      : CTRL3
* Address       : 0X22
* Bit Group Name: ST
* Permission    : RW
*******************************************************************************/
typedef enum 
{
    LIS2DS12_ST_NORMAL      = 0X00,
    LIS2DS12_ST_POS_SIGN    = 0X40,
    LIS2DS12_ST_NEG_SIGN    = 0X80,
    LIS2DS12_ST_NOT_AVAIL   = 0XC0,
} LIS2DS12_ST_enum_t;

#define LIS2DS12_ST_MASK  	0xC0

static TimerHandle_stu_t timerHandle = NULL;

static FunctionalState gsensor_status = DISABLE;
static uint8_t user_id =0;//谁使能禁能的

static void Gsensor_TimeoutDisable(TimerHandle_stu_t t);
static void Gsensor_Disable(void);

static ErrorStatus Gsensor_Read(uint8_t reg_addr, uint8_t *data, uint8_t len)
{
    if (Device_Write(IIC_VHW_GSENSOR, &reg_addr, 1, IIC_ADDR_GSENSOR) == 0)
    {
        return (Device_Read(IIC_VHW_GSENSOR, data, len, IIC_ADDR_GSENSOR) == 0) ? SUCCESS : ERROR;
    }
    return ERROR;
}

static ErrorStatus Gsensor_Write(uint8_t reg_addr, uint8_t *data, uint8_t len)
{
    uint8_t buffer[10] = {0};

    buffer[0] = reg_addr;
    memcpy(&buffer[1], data, len);
    return (Device_Write(IIC_VHW_GSENSOR, buffer, len+1, IIC_ADDR_GSENSOR) == 0) ? SUCCESS : ERROR;
}

static ErrorStatus Gsensor_SoftReset(void)
{
    ErrorStatus ret;
    uint8_t ctrl2 = 0;
    ret = Gsensor_Read(LIS2DS12_CTRL2, (uint8_t *)&ctrl2, 1);

    if (ret == SUCCESS)
    {
        ctrl2 |= 0x40;
        ret = Gsensor_Write(LIS2DS12_CTRL2, (uint8_t *)&ctrl2, 1);
    }
    return ret;
}

static ErrorStatus Gsensor_GetTapSrc(uint8_t *src)
{
    return Gsensor_Read(LIS2DS12_TAP_SRC, src, 1);
}

static void Gsensor_ConfigTap(void)
{
    /* config tap mode */
    Gsensor_SoftReset();
    OSAL_DelayUs(100);

    uint8_t value = 0x00;
    Gsensor_Write(LIS2DS12_CTRL1, (uint8_t *)&value, 1); //set data rate: disable

    value = 0x38 | 0x02;
    Gsensor_Write(LIS2DS12_CTRL3, (uint8_t *)&value, 1); //enable tap detection on X, Y, Z, set interrupt active low

    value = 0x40;
    Gsensor_Write(LIS2DS12_CTRL4, (uint8_t *)&value, 1); //enable single-tap on int1 pad

    value = 0x05;
    Gsensor_Write(LIS2DS12_TAP_6D_THS, (uint8_t *)&value, 1); //set tap threshold

    value = 0x06;
    Gsensor_Write(LIS2DS12_INT_DUR, (uint8_t *)&value, 1); //set quit/shock time
}


/**
  * @brief  Gsensor的INT触发后，执行这个函数
  *         
  * @note   判断sensor具体产生了哪个触发
  */
static uint32_t Gsensor_ProcessISR(void)
{
    uint8_t tap_src = 0;

    if (Gsensor_GetTapSrc(&tap_src) == SUCCESS)
    {
        if(tap_src & 0x40)
        {
            Gsensor_Disable();
            OSAL_TimerDelete(timerHandle);
            timerHandle = NULL; //敲门后，关闭Gsensor

            if (tap_src & 0x20)
            {
                GSENSOR_LOG("single tap\r\n");
                uint8_t  msg[2] = {0};
                msg[0] =1;
                msg[1] = user_id; 
                OSAL_MessagePublish(&msg, sizeof(msg));
                return 1;
            }
            else if(tap_src & 0x10)
            {
                GSENSOR_LOG("double tap\r\n");
                return 2;
            }
        }
    }
    return 0;
}

/**
  * @brief  INT引脚中断回调
  *         
  * @note   在中断里面执行的，这里一般设置ISR事件即可，不要做过多的逻辑
  */
static void Gsensor_IrqHandle(VirtualHardware_enum_t dev, void *data, uint32_t len)
{
    if (gsensor_status == ENABLE)
    {
        OSAL_EventCreateFromISR(COMP_GSENSOR);
    }
}

/**
  * @brief  唤醒回调
  *         
  * @note   休眠状态下INT触发：会执行这个CB
  * @return 返回0：不唤醒， 返回非0：唤醒
  */
static int32_t Gsensor_WakeHandle(uint32_t dev)
{
    if (gsensor_status == ENABLE)
    {
        return Gsensor_ProcessISR();
    }
    return 0;
}
COMPONENT_WAKEUP_EXPORT(COMP_GSENSOR, Gsensor_WakeHandle, IRQ_VHW_GSENSOR);

/**
  * @brief  加速度传感器初始化
  *         
  * @note   
  */
static void Gsensor_Init(void)
{
    static FlagStatus power_on = SET;

    if (power_on == SET)
    {
        power_on = RESET;

        /* read device id */
        uint8_t id = 0;
        Gsensor_Read(LIS2DS12_WHO_AM_I, &id, 1);
        if (id != LIS2DS12_ID)
        {
            GSENSOR_LOG("read id err, %02x\r\n", id);
            return;
        }
        
        /* 配置单击检测 */
        Gsensor_ConfigTap();

        /* 注册中断回调 */
        Device_RegisteredCB(IRQ_VHW_GSENSOR, Gsensor_IrqHandle);

        gsensor_status = DISABLE;
        GSENSOR_LOG("gsensor init success\r\n");
    }
}

static void Gsensor_Disable(void)
{
    uint8_t value = 0x00;
    Gsensor_Write(LIS2DS12_CTRL1, (uint8_t *)&value, 1); //set data rate: disable
}

static void Gsensor_Enable(void)
{
    uint8_t value = 0xC0;
    Gsensor_Write(LIS2DS12_CTRL1, (uint8_t *)&value, 1); //set data rate: 100Hz
}

static ErrorStatus Gsensor_SetLevel(uint8_t level)
{
    uint8_t value;

    if (level == 1)
    {
        value = 30;
    }
    else if (level == 2)
    {
        value = 20;
    }
    else if (level == 3)
    {
        value = 10;//最高震动灵敏度
    }
    else
    {
        return ERROR;
    }
    Gsensor_Write(LIS2DS12_TAP_6D_THS, (uint8_t *)&value, 1); //set tap threshold
    return SUCCESS;
}

static uint8_t Gsensor_GetLevel(void)
{
    uint8_t level =1;
    Gsensor_Read(LIS2DS12_TAP_6D_THS, (uint8_t *)&level, 1); //set tap threshold
    return level;
}
/**
  * @brief  设置Gsensor状态
  *    
  * @param  status：使能、禁能
  */
static ErrorStatus Gsensor_SetStatus(FunctionalState status, uint32_t time ,uint8_t userId)
{
    if (status == DISABLE)
    {
        Gsensor_Disable();
        gsensor_status = DISABLE;
        // user_id = userId;
        GSENSOR_LOG("gsensor disable\r\n");
    }
    else if (status == ENABLE)
    {
        Gsensor_Enable();
        gsensor_status = ENABLE;
        user_id = userId;
        GSENSOR_LOG("gsensor enable, time:%ld\r\n", time);

        timerHandle = OSAL_TimerCreate(Gsensor_TimeoutDisable, time * 1000, RESET);//创建定时时间，关闭gsensor
    }
    return SUCCESS;
}

static void Gsensor_TimeoutDisable(TimerHandle_stu_t t)
{
    (void)t;
    Gsensor_SetStatus(DISABLE, 0,0);
}

static ErrorStatus Gsensor_Write_ST(LIS2DS12_ST_enum_t newValue)
{
  uint8_t value;

  if( !Gsensor_Read(LIS2DS12_CTRL3, &value, 1) )
    return ERROR;

  value &= ~LIS2DS12_ST_MASK; 
  value |= newValue;
  
  if( !Gsensor_Write(LIS2DS12_CTRL3, &value, 1) )
    return ERROR;

  return SUCCESS;
}

/**
  * @brief  Gsensor自检是否功能正常
  *    
  * @param  status：使能、禁能
  */
static ErrorStatus Gsensor_self_test(void)
{
    static FlagStatus power_on = SET;
    ErrorStatus ret;
    int16_t dataN[3] = {0};//正常模式下的数据
    int16_t dataT[3] = {0};//self-test模式下的数据
    int32_t dataTemp;
    if (power_on == SET)
    {
        power_on = RESET;
        /* read device id */
        uint8_t id = 0;
        Gsensor_Read(LIS2DS12_WHO_AM_I, &id, 1);
        if (id != LIS2DS12_ID)
        {
            return ERROR;
        }
        Gsensor_SoftReset();
        OSAL_DelayUs(100);
        GSENSOR_LOG("gsensor init success\r\n");
    }
    //800Hz 2g
    uint8_t value = 0xF0;
    Gsensor_Write(LIS2DS12_CTRL1, (uint8_t *)&value, 1); 

    /* 设置为正常模式 */
    Gsensor_Write_ST(LIS2DS12_ST_NORMAL);
    Device_DelayMs(5);
    ret = Gsensor_Read(LIS2DS12_OUT_X_L, (uint8_t*)dataN, 6);
    if (ret == SUCCESS)
    {
        GSENSOR_LOG("dataN[0] = %d, dataN[1] = %d, dataN[2] = %d\r\n", dataN[0], dataN[1], dataN[2]);
    }

    /* 设置为self-test模式 */
    Gsensor_Write_ST(LIS2DS12_ST_POS_SIGN);
    Device_DelayMs(5);
    ret = Gsensor_Read(LIS2DS12_OUT_X_L, (uint8_t*)dataT, 6);
    if (ret == SUCCESS)
    {
        GSENSOR_LOG("dataT[0] = %d, dataT[1] = %d, dataT[2] = %d\r\n", dataT[0], dataT[1], dataT[2]);
    }
    
    dataTemp = dataT[0] - dataN[0];
    dataTemp = dataTemp * 1000 * 2;
    int16_t delta_x = (int16_t)(dataTemp / 0xffff);

    dataTemp = dataT[1] - dataN[1];
    dataTemp = dataTemp * 1000 * 2;
    int16_t delta_y = (int16_t)(dataTemp / 0xffff);

    dataTemp = dataT[2] - dataN[2];
    dataTemp = dataTemp * 1000 * 2;
    int16_t delta_z = (int16_t)(dataTemp / 0xffff);

    GSENSOR_LOG("delta_x = %d,  delta_y = %d, delta_z = %d \r\n", delta_x, delta_y, delta_z);
    if (delta_x < 70 || delta_x > 1500 || delta_y < 70 || delta_y > 1500 || delta_z < 70 || delta_z > 1500)
    {
        GSENSOR_LOG("gsensor self test error\r\n");
        return ERROR;
    }
    else
    {
        GSENSOR_LOG("gsensor self test succeed\r\n");
        return SUCCESS;
    }
    return SUCCESS;
}

/**
  * @brief  加速度传感器任务函数
  *
  * @note
  *         
  * @param  event：当前任务的所有事件
  *
  * @return 返回未处理的事件
  */
static uint32_t Gsensor_Task(uint32_t event)
{
	/* 系统启动事件 */
	if (event & EVENT_SYS_START)
	{
		GSENSOR_LOG("Gsensor task start\r\n");
		
        Gsensor_Init();
        Device_ConfigCB(IRQ_VHW_GSENSOR, ENABLE);
        SYS_API(Gsensor_SetStatus);
        SYS_API(Gsensor_SetLevel);
        SYS_API(Gsensor_self_test);
        SYS_API(Gsensor_GetLevel);
		return ( event ^ EVENT_SYS_START );
	}
	
	/* 系统休眠事件 */
	if (event & EVENT_SYS_SLEEP)
	{
        Device_ConfigCB(IRQ_VHW_GSENSOR, DISABLE);
		return ( event ^ EVENT_SYS_SLEEP );
	}
	
	/* 系统中断事件 */
	if (event & EVENT_SYS_ISR)
	{
        Gsensor_ProcessISR();
		return ( event ^ EVENT_SYS_ISR );
	}
	return 0;
}
COMPONENT_TASK_EXPORT(COMP_GSENSOR, Gsensor_Task, 0);
